#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <limits>
#include <algorithm>
using namespace std;

#include "common.h"
#include "scene.h"
#include "image.h"

namespace RAYTRACER
{


Color raytrace (Ray & ray, scene & myScene) 
{
	Color color ;
    float coef = 1.0f;
    int level = 0; 
        do 
        { 
            // Looking for the closest intersection : newStart, and the normal n ;
            int currentSphere= -1;
			int materialID = -1 ;
			Point3 newStart ;
			Vector3 normal ;

			if (! myScene.intersect(ray, newStart, normal, currentSphere, materialID))
				break;
            material currentMat = myScene.materialContainer[materialID]; 

            // Compute the color of the intersection point ;
            for (unsigned int j = 0; j < myScene.lightContainer.size(); ++j) {
                light current = myScene.lightContainer[j];
                Vector3 dist = current.pos - newStart;
                if (normal * dist <= 0.0f)
                    continue;
                float t = dist.length();
                if ( t <= 0.0f )
                    continue;
                Ray lightRay (newStart, dist.normal());

                // computation of the shadows
                bool inShadow = false; 
                for (unsigned int i = 0; i < myScene.sphereContainer.size(); ++i) {
					if (myScene.sphereContainer[i].intersect(lightRay,  t)) 
					{
                        inShadow = true;
                        break;
                    }
                }
                if (!inShadow) {
                    // lambert Model 
                    float lambert = (lightRay.dir * normal) * coef;
					color += lambert * current.color * currentMat.color ;
                }
            }

            // Tracing the reflection light
            coef *= currentMat.reflection;
            float reflet = 2.0f * (ray.dir * normal);
            ray.start = newStart;
            ray.dir = ray.dir - reflet * normal;

            level++;
        } 
        while ((coef > 0.0f) && (level < 5));   
		return color ;
}
bool scan(char* outputName, scene &myScene) 
{
	TGA tga (outputName);
	tga.writeHeadUnCompressed(myScene.sizex, myScene.sizey);

    // Scanning 
    for (int y = 0; y < myScene.sizey; ++y) 
	{ 
	    for (int x = 0; x < myScene.sizex; ++x) 
		{
			Ray viewRay ( Point3(float(x), float(y), -1000.0f), Vector3( 0.0f, 0.0f, 1.0f));
			Color color = raytrace(viewRay, myScene);
			tga.writePixel(color);
	    }
    }
    return true;
}

}

int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        cout << "Usage : "<<argv[0]<<" filename.tga" << endl;
        return -1;
    }
	RAYTRACER::scene myScene;
    if (!init(myScene))
    {
        cout << "Failure when reading the Scene file." << endl;
        return -1;
    }
    if (!RAYTRACER::scan(argv[1], myScene))
    {
        cout << "Failure when creating the image file." << endl;
        return -1;
    }
    return 0;
}
